import com.powerfl.frm.taf.*;

//render Activate
static private var raDeactive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var raActive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var raRemove:Vector.<TAFtween> = new Vector.<TAFtween>();
//render Deactivate
static private var rdDeactive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var rdActive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var rdRemove:Vector.<TAFtween> = new Vector.<TAFtween>();
//render Fixed
static private var rfDeactive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var rfActive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var rfRemove:Vector.<TAFtween> = new Vector.<TAFtween>();
//logic Activate
static private var laDeactive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var laActive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var laRemove:Vector.<TAFtween> = new Vector.<TAFtween>();
//logic Deactivate
static private var ldDeactive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var ldActive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var ldRemove:Vector.<TAFtween> = new Vector.<TAFtween>();
//logic Fixed
static private var lfDeactive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var lfActive:Vector.<TAFtween> = new Vector.<TAFtween>();
static private var lfRemove:Vector.<TAFtween> = new Vector.<TAFtween>();

static private var timeline:Object = {};

static private var objects:Dictionary = new Dictionary( true );
static private var isPause:int = -1;//0 포즈상태 -1 실행상태
static private var empty:Object = {};

static internal function TIMELINE( $key:String, $times:Array, $mask:Array ):void{
	var i:int, j:int, times:Array, delay:Number, ease:Function;
	if( timeline[$key] ){
		TAF.SELF.error( '이미 존재하는 타임라인입니다 - ' + $key );
	}else{
		times = []; 
		if( $mask ){
			delay = 0;
			for( i = 0, j = $mask.length ; i < j ; ++i ){
				if( $mask[i] === 'D' ){
					delay = $times[i]; 
				}else{
					if( $mask[i] in TAFtween ){
						ease = TAFtween[$mask[i]];
					}else{
						ease = null;
					}
					times[times.length] = {time:$times[i], delay:delay, ease:ease};
					
					delay = 0;
				}
			}
		}else{
			for( i = 0, j = $times.length ; i < j ; ++i ){
				times[times.length] = {time:$times[i], delay:0};
			}
		}
		timeline[$key] = [];
		timeline[$key][0] = {time:1/( ( times[0].time - times[0].delay )*1000 ), delay:times[0].delay*1000, ease:times[0].ease};
		for( i = 1, j = times.length ; i < j ; ++i ){
			timeline[$key][i] = {ease:times[i].ease};
			if( times[i].delay ){
				timeline[$key][i].time = 1/( ( times[i].time - times[i].delay )*1000 );
				timeline[$key][i].delay = ( times[i].delay - times[i-1].time )*1000;
			}else{
				timeline[$key][i].time = 1/( ( times[i].time - times[i-1].time )*1000 );
				timeline[$key][i].delay = 0;
			}
		}
	}
}
static internal function setRenderActivate( $object:Object, $id:String, $timeline:String, $param:TAFparam ):TAFtween{
	return set_( 'RA', raActive, raDeactive, $object, $id, $timeline, $param );
}
static internal function setRenderDectivate( $object:Object, $id:String, $timeline:String, $param:TAFparam ):TAFtween{
	return set_( 'RD', rdActive, rdDeactive, $object, $id, $timeline, $param );
}
static internal function setRenderFixed( $object:Object, $id:String, $timeline:String, $param:TAFparam ):TAFtween{
	return set_( 'RF', rfActive, rfDeactive, $object, $id, $timeline, $param );
}
static internal function setLogicActivate( $object:Object, $id:String, $timeline:String, $param:TAFparam ):TAFtween{
	return set_( 'LA', laActive, laDeactive, $object, $id, $timeline, $param );
}
static internal function setLogicDectivate( $object:Object, $id:String, $timeline:String, $param:TAFparam ):TAFtween{
	return set_( 'LD', ldActive, ldDeactive, $object, $id, $timeline, $param );
}
static internal function setLogicFixed( $object:Object, $id:String, $timeline:String, $param:TAFparam ):TAFtween{
	return set_( 'LF', lfActive, lfDeactive, $object, $id, $timeline, $param );
}
static private function set_( $key:String, $active:Vector.<TAFtween>, $deactive:Vector.<TAFtween>, $object:Object, $id:String, $timeline:String, $param:TAFparam ):TAFtween{
	var instance:TAFtween, key:*, autoCollect:int, v:TAFtweenVar, prevTime:Number, prevEase:Function;
	v = $param.vars;
	if( v === null ){
		TAF.SELF.error( 'tween인자가 주어지지 않았습니다.' );
	}
	if( $deactive.length ){
		instance = $deactive.pop();
	}else{
		instance = new TAFtween;
	}
	$active[$active.length] = instance;
	do{
		instance._tweens[instance._tweens.length] = v;
		if( v.time < 0 ){
			v.time = prevTime;
		}
		if( v.ease === null ){
			v.ease = prevEase;
		}
		prevTime = v.time;
		prevEase = v.ease;
	}while( v = v.next );
	instance._len = instance._tweens.length;
	
	if( $timeline ){
		if( timeline[$timeline] ){
			if( timeline[$timeline].length === instance._len ){
				instance._timeline =  timeline[$timeline];
			}else{
				TAF.SELF.error( '타임라인의 길이와 인자의 갯수가 일치하지 않습니다 - 타임라인:' +  timeline[$timeline].length + ', 인자갯수:' + instance._len );
			}
		}else{
			TAF.SELF.error( '정의되지 않은 타임라인 입니다 - ' + $timeline );
		}
	}
	
	instance._object = $object;
	instance._id = $id;
	instance.init();
	
	if( objects[$object] ){}else{
		objects[$object] = new tweenObject;
	}
	objects[$object][$key][objects[$object][$key].length] = $active.length - 1;
	
	switch( $key ){
	case'RA': TAF.SELF.bindRenderActivate('@@TWEEN_' + $key ); break;
	case'RD': TAF.SELF.bindRenderDeactivate('@@TWEEN_' + $key ); break;
	case'RF': TAF.SELF.bindRenderFixed('@@TWEEN_' + $key ); break;
	case'LA': TAF.SELF.bindLogicActivate('@@TWEEN_' + $key ); break;
	case'LD': TAF.SELF.bindLogicDeactivate('@@TWEEN_' + $key ); break;
	case'LF': TAF.SELF.bindLogicFixed('@@TWEEN_' + $key ); break;
	}
	
	if( $key.charAt(1) === 'F' ){}else{
		TAF.SELF.bindActivate( '@@TWEEN_' + $key + '_A' );
		TAF.SELF.bindDeactivate( '@@TWEEN_' + $key + '_D' );
	}
	return instance;
}
static internal function runRA():void{
	run_( 'RA', raActive, raDeactive, raRemove );
}
static internal function runRD():void{
	run_( 'RD', rdActive, rdDeactive, rdRemove );
}
static internal function runRF():void{
	run_( 'RF', rfActive, rfDeactive, rfRemove );
}
static internal function runLA():void{
	run_( 'LA', laActive, laDeactive, laRemove );
}
static internal function runLD():void{
	run_( 'LD', ldActive, ldDeactive, ldRemove );
}
static internal function runLF():void{
	run_( 'LF', lfActive, lfDeactive, lfRemove );
}
static private function run_( $key:String, $active:Vector.<TAFtween>, $deactive:Vector.<TAFtween>, $remove:Vector.<TAFtween> ):void{
	var i:int, j:int, temp:Array, tween:TAFtween;
	if( isPause < 0 ){
		if( $active.length ){
			$remove.length = 0;
			for( i = 0 ; i < $active.length ; ++i  ){
				tween = $active[i];
				if( tween.ease() < 0 ){
					$remove[$remove.length] = tween;
					if( tween._object ){
						temp = objects[tween._object][$key]; 
						temp.splice( temp.indexOf( i ), 1 );
					}else{
						return;
					}
				}
			}
			if( $remove.length ){
				for( i = $remove.length - 1 ; i > -1 ; --i ){
					$deactive[$deactive.length] = $active.splice( $active.indexOf( $remove[i] ), 1 )[0].collect();
				}
				if( $active.length ){}else{
					switch( $key ){
					case'RA': TAF.SELF.unbindRenderActivate('@@TWEEN_' + $key ); break;
					case'RD': TAF.SELF.unbindRenderDeactivate('@@TWEEN_' + $key ); break;
					case'RF': TAF.SELF.unbindRenderFixed('@@TWEEN_' + $key ); break;
					case'LA': TAF.SELF.unbindLogicActivate('@@TWEEN_' + $key ); break;
					case'LD': TAF.SELF.unbindLogicDeactivate('@@TWEEN_' + $key ); break;
					case'LF': TAF.SELF.unbindLogicFixed('@@TWEEN_' + $key ); break;
					}
					if( $key.charAt(1) === 'F' ){}else{
						TAF.SELF.unbindActivate( '@@TWEEN_' + $key + '_A' );
						TAF.SELF.unbindDeactivate( '@@TWEEN_' + $key + '_D' );
					}
				}
			}
		}
	}
}
static internal function PAUSE_RA():void{
	pause_( raActive );
}
static internal function PAUSE_RD():void{
	pause_( rdActive );
}
static internal function PAUSE_LA():void{
	pause_( laActive );
}
static internal function PAUSE_LD():void{
	pause_( ldActive );
}
static private function pause_( $active:Vector.<TAFtween> ):void{
	var i:int, j:int;
	for( i = 0, j = $active.length ; i < j ; ++i  ){
		$active[i].pause();
	}
}
static internal function RESUME_RA():void{
	resume_( raActive );
}
static internal function RESUME_RD():void{
	resume_( rdActive );
}
static internal function RESUME_LA():void{
	resume_( laActive );
}
static internal function RESUME_LD():void{
	resume_( ldActive );
}
static private function resume_( $active:Vector.<TAFtween> ):void{
	var i:int, j:int;
	for( i = 0, j = $active.length ; i < j ; ++i  ){
		$active[i].resume();
	}
}
static internal function PAUSE( $object:Object = null ):void{
	var i:int, j:int, temp:Array;
	if( $object ){
		temp = objects[$object].RA;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			raActive[temp[i]].pause();
		}
		temp = objects[$object].RD;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			rdActive[temp[i]].pause();
		}
		temp = objects[$object].RF;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			rfActive[temp[i]].pause();
		}
		temp = objects[$object].LA;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			laActive[temp[i]].pause();
		}
		temp = objects[$object].LD;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			ldActive[temp[i]].pause();
		}
		temp = objects[$object].LF;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			lfActive[temp[i]].pause();
		}
	}else{
		for( i = 0, j = raActive.length ; i < j ; ++i  ){
			raActive[i].pause();
		}
		for( i = 0, j = rdActive.length ; i < j ; ++i  ){
			rdActive[i].pause();
		}
		for( i = 0, j = rfActive.length ; i < j ; ++i  ){
			rfActive[i].pause();
		}
		for( i = 0, j = laActive.length ; i < j ; ++i  ){
			laActive[i].pause();
		}
		for( i = 0, j = ldActive.length ; i < j ; ++i  ){
			ldActive[i].pause();
		}
		for( i = 0, j = lfActive.length ; i < j ; ++i  ){
			lfActive[i].pause();
		}
		isPause = 0;
	}
	
}
static internal function RESUME( $object:Object = null ):void{
	var i:int, j:int, temp:Array;
	if( $object ){
		temp = objects[$object].RA;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			raActive[temp[i]].resume();
		}
		temp = objects[$object].RD;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			rdActive[temp[i]].resume();
		}
		temp = objects[$object].RF;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			rfActive[temp[i]].resume();
		}
		temp = objects[$object].LA;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			laActive[temp[i]].resume();
		}
		temp = objects[$object].LD;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			ldActive[temp[i]].resume();
		}
		temp = objects[$object].LF;
		for( i = 0, j = temp.length ; i < j ; ++i  ){
			lfActive[temp[i]].resume();
		}
	}else{
		for( i = 0, j = raActive.length ; i < j ; ++i  ){
			raActive[i].resume();
		}
		for( i = 0, j = rdActive.length ; i < j ; ++i  ){
			rdActive[i].resume();
		}
		for( i = 0, j = rfActive.length ; i < j ; ++i  ){
			rfActive[i].resume();
		}
		for( i = 0, j = laActive.length ; i < j ; ++i  ){
			laActive[i].resume();
		}
		for( i = 0, j = ldActive.length ; i < j ; ++i  ){
			ldActive[i].resume();
		}
		for( i = 0, j = lfActive.length ; i < j ; ++i  ){
			lfActive[i].resume();
		}
		isPause = -1;
	}
}
static internal function REMOVEALL( $setComplete:Boolean = false ):void{
	var i:int, j:int, key:*;
	
	if( $setComplete ){
		for( i = 0, j = raActive.length ; i < j ; ++i  ){
			raActive[i].end();
		}
		for( i = 0, j = rdActive.length ; i < j ; ++i  ){
			rdActive[i].end();
		}
		for( i = 0, j = rfActive.length ; i < j ; ++i  ){
			rfActive[i].end();
		}
		for( i = 0, j = laActive.length ; i < j ; ++i  ){
			laActive[i].end();
		}
		for( i = 0, j = ldActive.length ; i < j ; ++i  ){
			ldActive[i].end();
		}
		for( i = 0, j = lfActive.length ; i < j ; ++i  ){
			lfActive[i].end();
		}
	}
	for each( key in raActive ) key.collect();
	raDeactive.concat( raActive );
	raActive.length = 0;
	for each( key in rdActive ) key.collect();
	rdDeactive.concat( rdActive );
	rdActive.length = 0;
	for each( key in rfActive ) key.collect();
	rfDeactive.concat( rfActive );
	rfActive.length = 0;
	for each( key in laActive ) key.collect();
	laDeactive.concat( laActive );
	laActive.length = 0;
	for each( key in ldActive ) key.collect();
	ldDeactive.concat( ldActive );
	ldActive.length = 0;
	for each( key in lfActive ) key.collect();
	lfDeactive.concat( lfActive );
	lfActive.length = 0;
	
	objects = new Dictionary( true );
}
static internal function REMOVE( $object:Object, $setComplete:Boolean = false ):void{
	var i:int, temp:Array;
	temp = objects[$object].RA;
	for( i = temp.length - 1 ; i > -1 ; --i ){
		if( $setComplete ){
			raActive[temp[i]].end();
		}
		raDeactive[raDeactive.length] = raActive.splice( temp[i], 1 )[0].collect();
	}
	temp = objects[$object].RD;
	for( i = temp.length - 1 ; i > -1 ; --i ){
		if( $setComplete ){
			rdActive[temp[i]].end();
		}
		rdDeactive[rdDeactive.length] = rdActive.splice( temp[i], 1 )[0].collect();
	}
	temp = objects[$object].RF;
	for( i = temp.length - 1 ; i > -1 ; --i ){
		if( $setComplete ){
			rfActive[temp[i]].end();
		}
		rfDeactive[rfDeactive.length] = rfActive.splice( temp[i], 1 )[0].collect();
	}
	temp = objects[$object].LA;
	for( i = temp.length - 1 ; i > -1 ; --i ){
		if( $setComplete ){
			laActive[temp[i]].end();
		}
		laDeactive[laDeactive.length] = laActive.splice( temp[i], 1 )[0].collect();
	}
	temp = objects[$object].LD;
	for( i = temp.length - 1 ; i > -1 ; --i ){
		if( $setComplete ){
			ldActive[temp[i]].end();
		}
		ldDeactive[ldDeactive.length] = ldActive.splice( temp[i], 1 )[0].collect();
	}
	temp = objects[$object].LF;
	for( i = temp.length - 1 ; i > -1 ; --i ){
		if( $setComplete ){
			lfActive[temp[i]].end();
		}
		lfDeactive[lfDeactive.length] = lfActive.splice( temp[i], 1 )[0].collect();
	}
	objects[$object].clear();
}